/// 在 Rust 中，使用恐慌安全(Panic Safety) 来代替异常安全的说法。
/// 虽然在 Rust 中可以保证基本的恐慌安全，但还是有很多代码会引发恐慌，比如对 None 进行 unwrap 操作 、
/// 除以 0等， 这些恐慌发生在 Safe Rust中是没有问题的， Rust提供了一个口叫作UnwindSafe的标记 trait，
/// 专门用来标记那些恐慌安全的类型。但是在Unsafe Rust中就需要小心了，这里是Rust编译器鞭长莫及的地方
/// Rust 也提供了 catch unwind 方法来让开发者捕获恐慌，恢复当前线程。 Rust 团队在引入 catch_unwind方法时考虑了很
/// 多关于内存安全的问题 ，所以该方法只针对那些实现了 Unwind Safe的类型。这样做其实是为了避免开发者滥用
/// catch_unwind, Rust并不希望开发者把catch_unwind当作处理错误的惯用方法。万一将catch_unwind方法用于恐慌不安全的代码，
/// 则会导致内存不安全。除trait限定之外，还有一些恐慌是 catch_unwind无法捕获的。 比如在一些嵌入式平台中 ，
/// 恐慌是使用 abort (进程中止)来引发的，并不存在栈回退，所以也就无法捕获了
pub fn start() {
    use std::panic;
    let ok = panic::catch_unwind(|| println!("test"));
    let err = panic::catch_unwind(|| panic!("test"));
    assert!(ok.is_ok());
    assert!(err.is_err());

    // catch_unwind 接收的闭包会通过 panic!宏 引发恐慌，但是 catch_unwind 会 捕获此恐慌，并恢复当前线程
    // 所以可以打印下面的语句
    println!("end of main");

    // 看得出来，虽然在输出结果中打印了恐慌信息，但是并没有影响到后续代码的执行 。
    // 如果想消除此恐慌信息， 则可以使用 std::panic::set_hook方法来自定义消息，并把错误消息输出到标准错误流中
    let ok = panic::catch_unwind(|| println!("test"));
    panic::set_hook(Box::new(|panic_info| {
        if let Some(location) = panic_info.location() {
            println!(
                "Panic occurred '{}' at '{}' line",
                location.file(),
                location.line()
            );
        } else {
            println!("can ’ t get location information ...");
        }
    }));
    let err = panic::catch_unwind(|| panic!("test"));
    // catch_unwind 接收的闭包会通过 panic!宏 引发恐慌，但是 catch_unwind 会 捕获此恐慌，并恢复当前线程
    // 所以可以打印下面的语句
    println!("end of main");
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_panic() {
        super::start();
    }
}
